package com.yjy.controller;

import cn.hutool.http.HttpUtil;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

@RestController
public class TestController {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate redisTemplate;

    public static volatile int num = 100;

    // http://localhost:8088/test?key=name&value=testAA
    @RequestMapping("/test")
    public String add(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
        return (String) redisTemplate.opsForValue().get(key);
    }

    // http://localhost:8088/addUser?name=testAA&age=23
    @RequestMapping("/addUser")
    public User testUser(User user) {
        user.setCreateTime(new Date());
        redisTemplate.opsForValue().set("user:" + user.getName(), user);
        return (User) redisTemplate.opsForValue().get("user:" + user.getName());
    }

    // 测试可重入锁
    @GetMapping("/testRLock")
    public String order() throws InterruptedException {
        RLock lock = redissonClient.getLock("test:redissonLock");
        /*
            lock.lock(); // 最常见的使用方法
            lock.lock(10, TimeUnit.SECONDS); // 支持过期解锁功能，10s后自动解锁，无需调用unlock方法手动解锁
            lock.tryLock(500, TimeUnit.MILLISECONDS) // 尝试枷锁，500毫秒内获取不到则返回false
            lick.tryLock(3, 10, TimeUnit.SECONDS); // 尝试加锁，3秒内获取不到锁则直接返回false，加锁10s后自动解锁
         */
        if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
            System.out.println("加锁成功！");
            try {
                // 步骤2：处理逻辑。。。
                if (num >= 0) {
                    String result = String.format("线程%s 扣减库存:  总数：%s 扣减数：%s 剩余数：%s", Thread.currentThread().getName(), num, 1, num - 1);
                    System.out.println(result);
                    num--;
                    Thread.sleep(1000);
                    return result;
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("报错原因：：" + e.getMessage());
            } finally {
                // 步骤3：解锁
                lock.unlock();
            }
        }
        return "null";
    }

    // 压测，100条线程
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1000);
        final AtomicLong count = new AtomicLong(0L);
        ExecutorService taskExe = new ThreadPoolExecutor(10, 20, 100L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100),
                r -> new Thread(r, String.format("my-thread-%d", count.getAndIncrement())), new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < 1000; i++) {
            int finalI = i;
            taskExe.execute(() -> {
                String result = HttpUtil.get("localhost:8088/testRLock");
                System.out.println(Thread.currentThread().getName() + " 执行任务 " + finalI + " 返回结果：" + result);
                latch.countDown();
            });
        }

        latch.await();
        System.out.println("全部线程执行结束");
    }

    @Data
    public static class User {
        private String name;
        private Integer age;
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private Date createTime;
    }
}